package com.limi.java8.streams;

import com.limi.java8.lambda.practice.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 终止操作
 * @Author Limi Pan
 * @Date 2018-10-09 22:12
 * @Version v1.0
 */
public class StreamAPI3 {

    List<Employee> employees = Arrays.asList(
            new Employee("张三", 18, 8888.30, Employee.Status.FREE),
            new Employee("李四", 24, 12578.82, Employee.Status.BUSY),
            new Employee("王五", 23, 4623.96, Employee.Status.VOCATION),
            new Employee("赵六", 25, 6578.94, Employee.Status.FREE),
            new Employee("蒋七", 31, 9578.94, Employee.Status.BUSY),
            new Employee("蒋七", 31, 9578.94, Employee.Status.BUSY)
    );

    /*
     * 查找与匹配：
     * allMatch---检查是否匹配所有元素。
     * anyMatch---检查是否至少匹配一个元素。
     * noneMatch---检查是否没有匹配所有元素。
     * findFirst---返回第一个元素。
     * findAny---返回当前流中的任意元素。
     * count---返回流中元素的总个数。
     * max---返回流中最大值。
     * min---返回流中最小值。
     */
    @Test
    public void test(){
        boolean b1 = employees.stream()
                .allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);

        boolean b2 = employees.stream()
                .anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);

        boolean b3 = employees.stream()
                .noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b3);

        Optional<Employee> op = employees.stream()
                .sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op.get());

        Optional<Employee> op2 = employees.stream()
                .filter(e -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op2.get());
    }

    @Test
    public void test2(){
        long count = employees.stream()
                .count();
        System.out.println(count);

        Optional<Employee> op1 = employees.stream()
                //.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
                .max(Comparator.comparingDouble(Employee::getSalary));
        System.out.println(op1.get());

        Optional<Double> op2 = employees.stream()
                .map(Employee::getSalary)
                .min(Double::compare);
        System.out.println(op2.get());
    }

    /*
     * 归约
     * reduce(T identity, BinaryOperator) / reduce(BinaryOperator)
     * 可以将流中元素反复结合起来，得到一个值。
     */
    @Test
    public void test3(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        //map和reduce的连接通常称为map-reduce模式，因Google用它来进行网络搜索而出名
        //hadoop中的MapReduce
        Optional<Double> op = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(op.get());
    }

    /*
     * 收集
     * collect ---将流转换为其他形式。接收一个Collector接口的实现，用于给Stream中的元素做汇总的方法
     */
    @Test
    public void test4(){
        //收集到List结合中
        List<String> list = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        //list.forEach(System.out::println);

        //收集到Set集合中
        Set<String> set = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        //set.forEach(System.out::println);

        //收集到HashSet中
        HashSet<String> hashSet = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hashSet.forEach(System.out::println);

    }

    @Test
    public void test5(){
        //总数
        Long count = employees.stream()
                .collect(Collectors.counting());

        //平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));

        //总和
        DoubleSummaryStatistics sum = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));

        //最大值
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        //最小值
        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }

    @Test
    public void test6(){
        //分组
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        //System.out.println(map);//Map没有forEach

        //多级分组
        Map<Employee.Status, Map<String, List<Employee>>> map1 = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e1 -> {
                    if (((Employee) e1).getAge() <= 35) {
                        return "青年";
                    } else if (((Employee) e1).getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        //System.out.println(map1);

        //分区
        Map<Boolean, List<Employee>> map2 = employees.stream()
                .collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
        System.out.println(map2);
        

    }

    @Test
    public void test7(){
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());
        System.out.println(dss.getMin());
    }

    @Test
    public void test8(){
        //连接字符串
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","***","***"));
        System.out.println(str);
    }
}
